home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / gfx / pbm / pnmtopng.lha / src / pngtopnm.c < prev    next >
C/C++ Source or Header  |  1995-07-15  |  10KB  |  382 lines

  1. /*
  2. ** pngtopnm.c - read a Portable Network Graphics file and produce a portable
  3. ** anymap
  4. **
  5. ** Copyright (C) 1995 Alexander Lehmann
  6. **
  7. ** Permission to use, copy, modify, and distribute this software and its
  8. ** documentation for any purpose and without fee is hereby granted, provided
  9. ** that the above copyright notice appear in all copies and that both that
  10. ** copyright notice and this permission notice appear in supporting
  11. ** documentation.  This software is provided "as is" without express or
  12. ** implied warranty.
  13. **
  14. ** modeled after giftopnm by David Koblas and
  15. ** with lots of bits pasted from pnglib.txt by Guy Eric Schalnat
  16. */
  17.  
  18. #include "pnm.h"
  19. #include "png.h"
  20.  
  21. #define TRUE 1
  22. #define FALSE 0
  23.  
  24. enum alpha_handling
  25. { none, alpha_only, mix };
  26.  
  27. /* prototypes */
  28. static void store_pixel ARGS((xel *pix, png_uint_16 r, png_uint_16 g, png_uint_16 b, png_uint_16 a));
  29. static png_uint_16 _get_png_val ARGS((png_byte **pp, int bit_depth));
  30. static void print_text ARGS((png_info *info_ptr));
  31. static void convertPNG ARGS((FILE *in));
  32.  
  33. static int verbose=FALSE;
  34. static int text=FALSE;
  35.  
  36. static enum alpha_handling alpha=none;
  37.  
  38. static pixval maxval;
  39.  
  40. #define get_png_val(p) _get_png_val(&(p),info_ptr->bit_depth)
  41.  
  42. static
  43. #ifdef __STDC__
  44. png_uint_16 _get_png_val(png_byte **pp, int bit_depth)
  45. #else
  46. png_uint_16 _get_png_val(pp, bit_depth)
  47. png_byte **pp;
  48. int bit_depth;
  49. #endif
  50. {
  51.   png_uint_16 c=0;
  52.  
  53.   if(bit_depth==16) {
  54.     c=(*((*pp)++))<<8;
  55.   }
  56.   c|=(*((*pp)++));
  57.  
  58.   return c;
  59. }
  60.  
  61. static
  62. #ifdef __STD__
  63. void store_pixel(xel *pix, png_uint_16 r, png_uint_16 g, png_uint_16 b, png_uint_16 a)
  64. #else
  65. void store_pixel(pix, r, g, b, a)
  66. xel *pix;
  67. png_uint_16 r, g, b, a;
  68. #endif
  69. {
  70.   if(alpha==alpha_only) {
  71.     PNM_ASSIGN1(*pix, a);
  72.   } else
  73.   if(alpha==mix) {
  74.     r*=(double)a/maxval;
  75.     g*=(double)a/maxval;
  76.     b*=(double)a/maxval;
  77.     PPM_ASSIGN(*pix, r, g, b);
  78.   } else {
  79.     PPM_ASSIGN(*pix, r, g, b);
  80.   }
  81. }
  82.  
  83. static
  84. #ifdef __STDC__
  85. void print_text(png_info *info_ptr)
  86. #else
  87. void print_text(info_ptr)
  88. png_info *info_ptr;
  89. #endif
  90. {
  91.   int i;
  92.   static char *month[]=
  93.     {"January", "Feburary", "March", "April", "May", "June", "July", "August",
  94.        "September", "October", "November", "December"};
  95.  
  96.   for(i=0;i<info_ptr->num_text;i++) {
  97.     pm_message("\n%s:%.*s", info_ptr->text[i].key,
  98.                (int)info_ptr->text[i].text_length,
  99.                info_ptr->text[i].text);
  100.   }
  101.  
  102.   if(info_ptr->valid & PNG_INFO_tIME) {
  103.     pm_message("modification time: %02d %s %d %02d:%02d:%02d",
  104.                info_ptr->mod_time.day, month[info_ptr->mod_time.month],
  105.                info_ptr->mod_time.year, info_ptr->mod_time.hour,
  106.                info_ptr->mod_time.minute, info_ptr->mod_time.second);
  107.   }
  108. }
  109.  
  110. static
  111. #ifdef __STDC__
  112. void convertPNG(FILE *in)
  113. #else
  114. void convertPNG(in)
  115. FILE *in;
  116. #endif
  117. {
  118.   png_struct *png_ptr = malloc(sizeof (png_struct));
  119.   png_info *info_ptr = malloc(sizeof (png_info));
  120.   pixel *row;
  121.   png_byte **png_image;
  122.   png_byte *png_pixel;
  123.   pixel *pnm_pixel;
  124.   int x,y;
  125.   int linesize;
  126.   png_uint_16 c,c2,c3,a;
  127.   int pnm_type;
  128.   int i;
  129.   char *type_string;
  130.   char *alpha_string;
  131.  
  132.   if(png_ptr==NULL || info_ptr==NULL)
  133.     pm_error("Cannot allocate PNGLIB structures");
  134.  
  135.   if(setjmp(png_ptr->jmpbuf)==0) {
  136.     png_read_init(png_ptr);
  137.     png_info_init(info_ptr);
  138.     png_init_io(png_ptr, in);
  139.     png_read_info(png_ptr, info_ptr);
  140.  
  141.     if(verbose) {
  142.       switch(info_ptr->color_type) {
  143.         case PNG_COLOR_TYPE_GRAY:
  144.           type_string="gray";
  145.           alpha_string="";
  146.           break;
  147.  
  148.         case PNG_COLOR_TYPE_GRAY_ALPHA:
  149.           type_string="gray";
  150.           alpha_string="+alpha";
  151.           break;
  152.  
  153.         case PNG_COLOR_TYPE_PALETTE:
  154.           type_string="palette";
  155.           alpha_string="";
  156.           break;
  157.  
  158.         case PNG_COLOR_TYPE_RGB:
  159.           type_string="truecolor";
  160.           alpha_string="";
  161.           break;
  162.  
  163.         case PNG_COLOR_TYPE_RGB_ALPHA:
  164.           type_string="truecolor";
  165.           alpha_string="+alpha";
  166.           break;
  167.       }
  168.       if(info_ptr->valid & PNG_INFO_tRNS) {
  169.         alpha_string="+transparency";
  170.       }
  171.  
  172.       pm_message("reading a %d x %d image, %d bit%s %s%s%s",
  173.                  info_ptr->width, info_ptr->height,
  174.                  info_ptr->bit_depth, info_ptr->bit_depth>1 ? "s" : "",
  175.                  type_string, alpha_string,
  176.                  info_ptr->interlace_type ? " Adam7 interlaced" : "");
  177.     }
  178.  
  179.     png_image=malloc(info_ptr->height*sizeof(png_byte*));
  180.     if(png_image==NULL)
  181.       pm_error("couldn't alloc space for image");
  182.  
  183.     if(info_ptr->bit_depth==16)
  184.       linesize=2*info_ptr->width;
  185.     else
  186.       linesize=info_ptr->width;
  187.  
  188.     if(info_ptr->color_type==PNG_COLOR_TYPE_GRAY_ALPHA)
  189.       linesize*=2;
  190.     else
  191.     if(info_ptr->color_type==PNG_COLOR_TYPE_RGB)
  192.       linesize*=3;
  193.     else
  194.     if(info_ptr->color_type==PNG_COLOR_TYPE_RGB_ALPHA)
  195.       linesize*=4;
  196.  
  197.     for(y=0;y<info_ptr->height;y++) {
  198.       png_image[y]=malloc(linesize);
  199.       if(png_image[y]==NULL)
  200.         pm_error("couldn't alloc space for image");
  201.     }
  202.  
  203.     if (info_ptr->bit_depth < 8)
  204.       png_set_packing(png_ptr);
  205.  
  206.     png_read_image(png_ptr, png_image);
  207.     png_read_end(png_ptr, info_ptr);
  208.  
  209.     if(text) {
  210.       print_text(info_ptr);
  211.     }
  212.  
  213.     if(info_ptr->valid & PNG_INFO_pHYs) {
  214.       float r;
  215.       r=(float) info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
  216.       if(r!=1.0) {
  217.         pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  218.                    r < 1.0 ? 'x' : 'y',
  219.                    r < 1.0 ? 1.0 / r : r );
  220.       }
  221.     }
  222.  
  223.     if ((row = pnm_allocrow(info_ptr->width)) == NULL)
  224.       pm_error("couldn't alloc space for image");
  225.  
  226.     if(info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
  227.       maxval=255;
  228.     } else {
  229.       maxval=(1l<<info_ptr->bit_depth)-1;
  230.     }
  231.  
  232.     if(alpha==alpha_only) {
  233.       if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
  234.          info_ptr->color_type == PNG_COLOR_TYPE_RGB) {
  235.         pnm_type=PBM_TYPE;
  236.       } else
  237.         if(info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
  238.           pnm_type=PBM_TYPE;
  239.           if(info_ptr->valid & PNG_INFO_tRNS) {
  240.             for(i=0;i<info_ptr->num_trans;i++) {
  241.               if(info_ptr->trans[i]!=0 && info_ptr->trans[i]!=maxval) {
  242.                 pnm_type=PGM_TYPE;
  243.                 break;
  244.               }
  245.             }
  246.           }
  247.         } else {
  248.           pnm_type=PGM_TYPE;
  249.         }
  250.     } else {
  251.       if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
  252.          info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
  253.         if(info_ptr->bit_depth == 1) {
  254.           pnm_type=PBM_TYPE;
  255.         } else {
  256.           pnm_type=PGM_TYPE;
  257.         }
  258.       } else {
  259.         pnm_type=PPM_TYPE;
  260.       }
  261.     }
  262.  
  263.     if (verbose)
  264.       pm_message("writing a %s file",
  265.                  pnm_type == PBM_TYPE ? "PBM" :
  266.                  pnm_type == PGM_TYPE ? "PGM" :
  267.                  pnm_type == PPM_TYPE ? "PPM" :
  268.                                                 "UNKNOWN!");
  269.  
  270.     pnm_writepnminit(stdout, info_ptr->width, info_ptr->height, maxval,
  271.                      pnm_type, FALSE);
  272.  
  273.     for(y=0;y<info_ptr->height;y++) {
  274.       png_pixel=png_image[y];
  275.       pnm_pixel=row;
  276.       for(x=0;x<info_ptr->width;x++) {
  277.         c=get_png_val(png_pixel);
  278.         switch(info_ptr->color_type) {
  279.           case PNG_COLOR_TYPE_GRAY:
  280.             store_pixel(pnm_pixel, c, c, c,
  281.                         (info_ptr->valid & PNG_INFO_tRNS) &&
  282.                          c==info_ptr->trans_values.gray ?
  283.                          0 : maxval);
  284.             break;
  285.  
  286.           case PNG_COLOR_TYPE_GRAY_ALPHA:
  287.             a=get_png_val(png_pixel);
  288.             store_pixel(pnm_pixel, c, c, c, a);
  289.             break;
  290.  
  291.           case PNG_COLOR_TYPE_PALETTE:
  292.             store_pixel(pnm_pixel, info_ptr->palette[c].red,
  293.                         info_ptr->palette[c].green, info_ptr->palette[c].blue,
  294.                         (info_ptr->valid & PNG_INFO_tRNS) &&
  295.                          c<info_ptr->num_trans ?
  296.                          info_ptr->trans[c] : maxval);
  297.             break;
  298.  
  299.           case PNG_COLOR_TYPE_RGB:
  300.             c2=get_png_val(png_pixel);
  301.             c3=get_png_val(png_pixel);
  302.             store_pixel(pnm_pixel, c, c2, c3,
  303.                         (info_ptr->valid & PNG_INFO_tRNS) &&
  304.                          c ==info_ptr->trans_values.red &&
  305.                          c2==info_ptr->trans_values.green &&
  306.                          c3==info_ptr->trans_values.blue ?
  307.                          0 : maxval);
  308.             break;
  309.  
  310.           case PNG_COLOR_TYPE_RGB_ALPHA:
  311.             c2=get_png_val(png_pixel);
  312.             c3=get_png_val(png_pixel);
  313.             a =get_png_val(png_pixel);
  314.             store_pixel(pnm_pixel, c, c2, c3, a);
  315.             break;
  316.  
  317.           default:
  318.             pm_error("unknown PNG color type");
  319.         }
  320.         pnm_pixel++;
  321.       }
  322.       pnm_writepnmrow(stdout, row, info_ptr->width, maxval, pnm_type, FALSE);
  323.     }
  324.     png_read_destroy(png_ptr, info_ptr, (png_info *)NULL);
  325.  
  326.     free(png_ptr);
  327.     free(info_ptr);
  328.   } else {
  329.     pm_error("setjmp returns error condition");
  330.   }
  331. }
  332.  
  333. #ifdef __STDC__
  334. int main(int argc, char *argv[])
  335. #else
  336. int main(argc, argv)
  337. int argc;
  338. char *argv[];
  339. #endif
  340. {
  341.   FILE *in;
  342.   int argn;
  343.   char *usage = "[-verbose] [-text] [-alpha|-mix] [pngfile]";
  344.  
  345.   pnm_init(&argc, argv);
  346.  
  347.   argn=1;
  348.   while(argn<argc && argv[argn][0]=='-' && argv[argn][1]!='\0') {
  349.     if(pm_keymatch(argv[argn], "-verbose", 2)) {
  350.       verbose=TRUE;
  351.     } else
  352.     if(pm_keymatch(argv[argn], "-text", 2)) {
  353.       text=TRUE;
  354.     } else
  355.     if(pm_keymatch(argv[argn], "-alpha", 2)) {
  356.       alpha=alpha_only;
  357.     } else
  358.     if(pm_keymatch(argv[argn], "-mix", 2)) {
  359.       alpha=mix;
  360.     } else {
  361.       pm_usage(usage);
  362.     }
  363.     argn++;
  364.   }
  365.  
  366.   if(argn != argc) {
  367.     in = pm_openr(argv[argn]);
  368.     ++argn;
  369.   } else {
  370.     in = stdin;
  371.   }
  372.  
  373.   if(argn != argc)
  374.     pm_usage(usage);
  375.  
  376.   convertPNG(in);
  377.   pm_close(in);
  378.   pm_close(stdout);
  379.   exit(0);
  380. }
  381.  
  382.